{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2.0.0\n",
      "sys.version_info(major=3, minor=7, micro=5, releaselevel='final', serial=0)\n",
      "numpy 1.16.4\n",
      "pandas 0.25.3\n",
      "sklearn 0.22\n",
      "tensorflow 2.0.0\n",
      "tensorflow_core.keras 2.2.4-tf\n",
      "Training Images ->  145462\n",
      "Validation Images ->  17972\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "import pandas as pd \n",
    "import os\n",
    "import matplotlib.pyplot as plt\n",
    "import sklearn\n",
    "import sys\n",
    "import tensorflow as tf\n",
    "import time\n",
    "import random\n",
    "import pathlib\n",
    "\n",
    "from tensorflow import keras\n",
    "\n",
    "print(tf.__version__)\n",
    "print(sys.version_info)\n",
    "for module in np, pd, sklearn, tf, keras:\n",
    "    print(module.__name__, module.__version__)\n",
    "\n",
    "\n",
    "training_path = pathlib.Path('./in_game_profile_dataset/training')\n",
    "validation_path = pathlib.Path('./in_game_profile_dataset/valid')\n",
    "\n",
    "train_image_paths = list(training_path.glob('*/*'))  \n",
    "valid_image_paths = list(validation_path.glob('*/*'))  \n",
    "\n",
    "train_image_paths = [str(path) for path in train_image_paths]\n",
    "valid_image_paths = [str(path) for path in valid_image_paths]\n",
    "\n",
    "random.shuffle(train_image_paths)\n",
    "random.shuffle(valid_image_paths)\n",
    "train_image_count = len(train_image_paths)\n",
    "valid_image_count = len(valid_image_paths)\n",
    "\n",
    "print(\"Training Images -> \", train_image_count)\n",
    "print(\"Validation Images -> \", valid_image_count)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['in_game_profile_dataset\\\\training\\\\Cassiopeia\\\\gray_2 - Copy - Copy (4) - Copy.png',\n",
       " 'in_game_profile_dataset\\\\training\\\\Katarina\\\\FbC6fe362d - Copy - Copy - Copy - Copy.png',\n",
       " 'in_game_profile_dataset\\\\training\\\\Xerath\\\\gray_4 - Copy (21) - Copy.png',\n",
       " 'in_game_profile_dataset\\\\training\\\\Taliyah\\\\F1ACcEf54a - Copy - Copy (4).png',\n",
       " 'in_game_profile_dataset\\\\training\\\\Miss Fortune\\\\04FA8e1EAC - Copy (2) - Copy.png']"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "train_image_paths[:5]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['in_game_profile_dataset\\\\valid\\\\Lee Sin\\\\gray_8.png',\n",
       " 'in_game_profile_dataset\\\\valid\\\\Zoe\\\\gray_40.png',\n",
       " 'in_game_profile_dataset\\\\valid\\\\Nami\\\\gray_10.png',\n",
       " 'in_game_profile_dataset\\\\valid\\\\Jhin\\\\55b556Dae7 - Copy (9).png',\n",
       " 'in_game_profile_dataset\\\\valid\\\\Thresh\\\\52EeC565bB - Copy.png']"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "valid_image_paths[:5]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['Aatrox',\n",
       " 'Ahri',\n",
       " 'Akali',\n",
       " 'Alistar',\n",
       " 'Amumu',\n",
       " 'Anivia',\n",
       " 'Annie',\n",
       " 'Aphelios',\n",
       " 'Ashe',\n",
       " 'Aurelion Sol',\n",
       " 'Azir',\n",
       " 'Bard',\n",
       " 'Blitzcrank',\n",
       " 'Brand',\n",
       " 'Braum',\n",
       " 'Caitlyn',\n",
       " 'Camille',\n",
       " 'Cassiopeia',\n",
       " \"Cho'Gath\",\n",
       " 'Corki',\n",
       " 'Darius',\n",
       " 'Diana',\n",
       " 'Dr. Mundo',\n",
       " 'Draven',\n",
       " 'Ekko',\n",
       " 'Elise',\n",
       " 'Evelynn',\n",
       " 'Ezreal',\n",
       " 'Fiddlesticks',\n",
       " 'Fiora',\n",
       " 'Fizz',\n",
       " 'Galio',\n",
       " 'Gangplank',\n",
       " 'Garen',\n",
       " 'Gnar',\n",
       " 'Gragas',\n",
       " 'Graves',\n",
       " 'Hecarim',\n",
       " 'Heimerdinger',\n",
       " 'Illaoi',\n",
       " 'Irelia',\n",
       " 'Ivern',\n",
       " 'Janna',\n",
       " 'Jarvan IV',\n",
       " 'Jax',\n",
       " 'Jayce',\n",
       " 'Jhin',\n",
       " 'Jinx',\n",
       " \"Kai'Sa\",\n",
       " 'Kalista',\n",
       " 'Karma',\n",
       " 'Karthus',\n",
       " 'Kassadin',\n",
       " 'Katarina',\n",
       " 'Kayle',\n",
       " 'Kayn',\n",
       " 'Kennen',\n",
       " \"Kha'Zix\",\n",
       " 'Kindred',\n",
       " 'Kled',\n",
       " \"Kog'Maw\",\n",
       " 'LeBlanc',\n",
       " 'Lee Sin',\n",
       " 'Leona',\n",
       " 'Lissandra',\n",
       " 'Lucian',\n",
       " 'Lulu',\n",
       " 'Lux',\n",
       " 'Malphite',\n",
       " 'Malzahar',\n",
       " 'Maokai',\n",
       " 'Master Yi',\n",
       " 'Miss Fortune',\n",
       " 'Mordekaiser',\n",
       " 'Morgana',\n",
       " 'Nami',\n",
       " 'Nasus',\n",
       " 'Nautilus',\n",
       " 'Neeko',\n",
       " 'Nidalee',\n",
       " 'Nocturne',\n",
       " 'Nunu & Willump',\n",
       " 'Olaf',\n",
       " 'Orianna',\n",
       " 'Ornn',\n",
       " 'Pantheon',\n",
       " 'Poppy',\n",
       " 'Pyke',\n",
       " 'Qiyana',\n",
       " 'Quinn',\n",
       " 'Rakan',\n",
       " 'Rammus',\n",
       " \"Rek'Sai\",\n",
       " 'Renekton',\n",
       " 'Rengar',\n",
       " 'Riven',\n",
       " 'Rumble',\n",
       " 'Ryze',\n",
       " 'Sejuani',\n",
       " 'Senna',\n",
       " 'Sett',\n",
       " 'Shaco',\n",
       " 'Shen',\n",
       " 'Shyvana',\n",
       " 'Singed',\n",
       " 'Sion',\n",
       " 'Sivir',\n",
       " 'Skarner',\n",
       " 'Sona',\n",
       " 'Soraka',\n",
       " 'Swain',\n",
       " 'Sylas',\n",
       " 'Syndra',\n",
       " 'Tahm Kench',\n",
       " 'Taliyah',\n",
       " 'Talon',\n",
       " 'Taric',\n",
       " 'Teemo',\n",
       " 'Thresh',\n",
       " 'Tristana',\n",
       " 'Trundle',\n",
       " 'Tryndamere',\n",
       " 'Twisted Fate',\n",
       " 'Twitch',\n",
       " 'Udyr',\n",
       " 'Unselected',\n",
       " 'Urgot',\n",
       " 'Varus',\n",
       " 'Vayne',\n",
       " 'Veigar',\n",
       " \"Vel'Koz\",\n",
       " 'Vi',\n",
       " 'Viktor',\n",
       " 'Vladimir',\n",
       " 'Volibear',\n",
       " 'Warwick',\n",
       " 'Wukong',\n",
       " 'Xayah',\n",
       " 'Xerath',\n",
       " 'Xin Zhao',\n",
       " 'Yasuo',\n",
       " 'Yorick',\n",
       " 'Yuumi',\n",
       " 'Zac',\n",
       " 'Zed',\n",
       " 'Ziggs',\n",
       " 'Zilean',\n",
       " 'Zoe',\n",
       " 'Zyra']"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "label_names = sorted(item.name for item in training_path.glob('*/') if item.is_dir())\n",
    "label_names"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "in_game_profile_dataset\\training\\Cassiopeia\\gray_2 - Copy - Copy (4) - Copy.png  --->   Cassiopeia\n",
      "in_game_profile_dataset\\training\\Katarina\\FbC6fe362d - Copy - Copy - Copy - Copy.png  --->   Katarina\n",
      "in_game_profile_dataset\\training\\Xerath\\gray_4 - Copy (21) - Copy.png  --->   Xerath\n",
      "in_game_profile_dataset\\training\\Taliyah\\F1ACcEf54a - Copy - Copy (4).png  --->   Taliyah\n",
      "in_game_profile_dataset\\training\\Miss Fortune\\04FA8e1EAC - Copy (2) - Copy.png  --->   Miss Fortune\n"
     ]
    }
   ],
   "source": [
    "training_image_labels = [pathlib.Path(path).parent.name for path in train_image_paths]\n",
    "for image, label in zip(train_image_paths[:5], training_image_labels[:5]):\n",
    "    print(image, ' --->  ', label)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "train_labels_info = []\n",
    "for image_path, label in zip(train_image_paths, training_image_labels):\n",
    "    train_labels_info.append((image_path, label))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[('in_game_profile_dataset\\\\training\\\\Cassiopeia\\\\gray_2 - Copy - Copy (4) - '\n",
      "  'Copy.png',\n",
      "  'Cassiopeia'),\n",
      " ('in_game_profile_dataset\\\\training\\\\Katarina\\\\FbC6fe362d - Copy - Copy - '\n",
      "  'Copy - Copy.png',\n",
      "  'Katarina'),\n",
      " ('in_game_profile_dataset\\\\training\\\\Xerath\\\\gray_4 - Copy (21) - Copy.png',\n",
      "  'Xerath'),\n",
      " ('in_game_profile_dataset\\\\training\\\\Taliyah\\\\F1ACcEf54a - Copy - Copy '\n",
      "  '(4).png',\n",
      "  'Taliyah'),\n",
      " ('in_game_profile_dataset\\\\training\\\\Miss Fortune\\\\04FA8e1EAC - Copy (2) - '\n",
      "  'Copy.png',\n",
      "  'Miss Fortune')]\n"
     ]
    }
   ],
   "source": [
    "import pprint\n",
    "pprint.pprint(train_labels_info[:5])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "in_game_profile_dataset\\valid\\Lee Sin\\gray_8.png  --->   Lee Sin\n",
      "in_game_profile_dataset\\valid\\Zoe\\gray_40.png  --->   Zoe\n",
      "in_game_profile_dataset\\valid\\Nami\\gray_10.png  --->   Nami\n",
      "in_game_profile_dataset\\valid\\Jhin\\55b556Dae7 - Copy (9).png  --->   Jhin\n",
      "in_game_profile_dataset\\valid\\Thresh\\52EeC565bB - Copy.png  --->   Thresh\n"
     ]
    }
   ],
   "source": [
    "valid_image_labels = [pathlib.Path(path).parent.name for path in valid_image_paths]\n",
    "for image, label in zip(valid_image_paths[:5], valid_image_labels[:5]):\n",
    "    print(image, ' --->  ', label)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "valid_labels_info = []\n",
    "for image_path, label in zip(valid_image_paths, valid_image_labels):\n",
    "    valid_labels_info.append((image_path, label))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[('in_game_profile_dataset\\\\valid\\\\Lee Sin\\\\gray_8.png', 'Lee Sin'),\n",
      " ('in_game_profile_dataset\\\\valid\\\\Zoe\\\\gray_40.png', 'Zoe'),\n",
      " ('in_game_profile_dataset\\\\valid\\\\Nami\\\\gray_10.png', 'Nami'),\n",
      " ('in_game_profile_dataset\\\\valid\\\\Jhin\\\\55b556Dae7 - Copy (9).png', 'Jhin'),\n",
      " ('in_game_profile_dataset\\\\valid\\\\Thresh\\\\52EeC565bB - Copy.png', 'Thresh')]\n"
     ]
    }
   ],
   "source": [
    "pprint.pprint(valid_labels_info[:5])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "                                            filepath         class\n",
      "0  in_game_profile_dataset\\training\\Cassiopeia\\gr...    Cassiopeia\n",
      "1  in_game_profile_dataset\\training\\Katarina\\FbC6...      Katarina\n",
      "2  in_game_profile_dataset\\training\\Xerath\\gray_4...        Xerath\n",
      "3  in_game_profile_dataset\\training\\Taliyah\\F1ACc...       Taliyah\n",
      "4  in_game_profile_dataset\\training\\Miss Fortune\\...  Miss Fortune\n",
      "                                            filepath    class\n",
      "0   in_game_profile_dataset\\valid\\Lee Sin\\gray_8.png  Lee Sin\n",
      "1      in_game_profile_dataset\\valid\\Zoe\\gray_40.png      Zoe\n",
      "2     in_game_profile_dataset\\valid\\Nami\\gray_10.png     Nami\n",
      "3  in_game_profile_dataset\\valid\\Jhin\\55b556Dae7 ...     Jhin\n",
      "4  in_game_profile_dataset\\valid\\Thresh\\52EeC565b...   Thresh\n"
     ]
    }
   ],
   "source": [
    "train_df = pd.DataFrame(train_labels_info)\n",
    "valid_df = pd.DataFrame(valid_labels_info)\n",
    "\n",
    "train_df.columns = valid_df.columns = ['filepath', 'class']\n",
    "\n",
    "print(train_df.head())\n",
    "print(valid_df.head())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Found 145462 validated image filenames belonging to 149 classes.\n",
      "Found 17972 validated image filenames belonging to 149 classes.\n"
     ]
    }
   ],
   "source": [
    "height = 60\n",
    "width = 60\n",
    "channels = 3\n",
    "batch_size = 128\n",
    "num_classes = 149\n",
    "\n",
    "train_datagen = keras.preprocessing.image.ImageDataGenerator(\n",
    "    #像素值 都除以255\n",
    "    rescale = 1./255,\n",
    "    # 图片随机旋转 (5度以内)\n",
    "    rotation_range = 20,\n",
    "    # 图片左右位移  20%限度以内\n",
    "    width_shift_range = 0.2,\n",
    "    # 图片上下位移  20%限度以内\n",
    "    height_shift_range = 0.2,\n",
    "    # 图像剪切强度\n",
    "    shear_range = 0.2,\n",
    "    # 图像缩放强度\n",
    "    zoom_range = 0.2,\n",
    "    # 是否水平翻转\n",
    "    horizontal_flip = False,\n",
    "    # 放大缩小吼， 像素填充方式\n",
    "    fill_mode = 'nearest',\n",
    ")\n",
    "\n",
    "train_generator = train_datagen.flow_from_dataframe(train_df, directory = './',\n",
    "                                                    x_col = 'filepath',\n",
    "                                                    y_col = 'class',\n",
    "                                                    classes = label_names,\n",
    "                                                    target_size = (height, width),\n",
    "                                                    batch_size = batch_size,\n",
    "                                                    seed = 2333,\n",
    "                                                    shuffle = True,\n",
    "                                                    class_mode = \"categorical\")\n",
    "\n",
    "valid_datagen = keras.preprocessing.image.ImageDataGenerator(\n",
    "    rescale = 1./255,\n",
    ")\n",
    "valid_generator = valid_datagen.flow_from_dataframe(valid_df, directory = './',\n",
    "                                                    x_col = 'filepath',\n",
    "                                                    y_col = 'class',\n",
    "                                                    classes = label_names,\n",
    "                                                    target_size = (height, width),\n",
    "                                                    batch_size = batch_size,\n",
    "                                                    seed = 666,\n",
    "                                                    shuffle = True,\n",
    "                                                    class_mode = \"categorical\")\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Training Generator Sample ->  145462\n",
      "Validation Generator Sample ->  17972\n"
     ]
    }
   ],
   "source": [
    "train_num = train_generator.samples\n",
    "valid_num = valid_generator.samples\n",
    "\n",
    "print(\"Training Generator Sample -> \", train_num)\n",
    "print(\"Validation Generator Sample -> \", valid_num)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(128, 60, 60, 3) (128, 149)\n",
      "[[0. 0. 0. ... 0. 0. 0.]\n",
      " [0. 0. 0. ... 0. 0. 0.]\n",
      " [0. 0. 0. ... 0. 0. 0.]\n",
      " ...\n",
      " [0. 0. 0. ... 0. 0. 0.]\n",
      " [0. 0. 0. ... 0. 0. 0.]\n",
      " [0. 0. 0. ... 0. 0. 0.]]\n",
      "(128, 60, 60, 3) (128, 149)\n",
      "[[0. 0. 0. ... 0. 0. 0.]\n",
      " [0. 0. 0. ... 0. 0. 0.]\n",
      " [0. 0. 0. ... 0. 0. 0.]\n",
      " ...\n",
      " [0. 0. 0. ... 0. 0. 0.]\n",
      " [0. 0. 0. ... 0. 0. 0.]\n",
      " [0. 0. 0. ... 0. 0. 0.]]\n"
     ]
    }
   ],
   "source": [
    "for i in range(2):\n",
    "    x, y = train_generator.next()\n",
    "    print(x.shape, y.shape)\n",
    "    print(y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Model: \"sequential\"\n",
      "_________________________________________________________________\n",
      "Layer (type)                 Output Shape              Param #   \n",
      "=================================================================\n",
      "conv2d (Conv2D)              (None, 60, 60, 16)        448       \n",
      "_________________________________________________________________\n",
      "conv2d_1 (Conv2D)            (None, 60, 60, 16)        2320      \n",
      "_________________________________________________________________\n",
      "max_pooling2d (MaxPooling2D) (None, 30, 30, 16)        0         \n",
      "_________________________________________________________________\n",
      "conv2d_2 (Conv2D)            (None, 30, 30, 32)        4640      \n",
      "_________________________________________________________________\n",
      "conv2d_3 (Conv2D)            (None, 30, 30, 32)        9248      \n",
      "_________________________________________________________________\n",
      "max_pooling2d_1 (MaxPooling2 (None, 15, 15, 32)        0         \n",
      "_________________________________________________________________\n",
      "conv2d_4 (Conv2D)            (None, 15, 15, 64)        18496     \n",
      "_________________________________________________________________\n",
      "conv2d_5 (Conv2D)            (None, 15, 15, 64)        36928     \n",
      "_________________________________________________________________\n",
      "max_pooling2d_2 (MaxPooling2 (None, 7, 7, 64)          0         \n",
      "_________________________________________________________________\n",
      "flatten (Flatten)            (None, 3136)              0         \n",
      "_________________________________________________________________\n",
      "dense (Dense)                (None, 128)               401536    \n",
      "_________________________________________________________________\n",
      "alpha_dropout (AlphaDropout) (None, 128)               0         \n",
      "_________________________________________________________________\n",
      "dense_1 (Dense)              (None, 149)               19221     \n",
      "=================================================================\n",
      "Total params: 492,837\n",
      "Trainable params: 492,837\n",
      "Non-trainable params: 0\n",
      "_________________________________________________________________\n"
     ]
    }
   ],
   "source": [
    "model = keras.models.Sequential([\n",
    "     \n",
    "    keras.layers.Conv2D(filters=16, kernel_size = 3, padding='same',\n",
    "                       activation = 'selu', input_shape = [width, height, channels]),\n",
    "    keras.layers.Conv2D(filters=16, kernel_size = 3, \n",
    "                        padding='same', activation = 'selu'),\n",
    "    keras.layers.MaxPool2D(pool_size=2),\n",
    "    \n",
    "    keras.layers.Conv2D(filters=32, kernel_size = 3, \n",
    "                        padding='same', activation = 'selu'),\n",
    "    keras.layers.Conv2D(filters=32, kernel_size = 3, \n",
    "                        padding='same', activation = 'selu'),\n",
    "    keras.layers.MaxPool2D(pool_size=2),\n",
    "    \n",
    "    keras.layers.Conv2D(filters=64, kernel_size = 3, padding='same',\n",
    "                       activation = 'selu', input_shape = [width, height, channels]),\n",
    "    keras.layers.Conv2D(filters=64, kernel_size = 3, \n",
    "                        padding='same', activation = 'selu'),\n",
    "    keras.layers.MaxPool2D(pool_size=2),\n",
    "    \n",
    "    keras.layers.Flatten(),\n",
    "    keras.layers.Dense(128, activation = 'selu'),\n",
    "    keras.layers.AlphaDropout(rate=0.5),\n",
    "    \n",
    "    keras.layers.Dense(num_classes, activation = 'softmax')\n",
    "])\n",
    "\n",
    "model.compile(loss=\"categorical_crossentropy\",\n",
    "             optimizer = \"adam\", metrics = ['accuracy'])\n",
    "\n",
    "model.summary()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "logdir = './face_recognition'\n",
    "if not os.path.exists(logdir):\n",
    "    os.mkdir(logdir)\n",
    "\n",
    "output_model_file = os.path.join(logdir, \"face_recognition_model.h5\")\n",
    "\n",
    "callbacks = [\n",
    "    keras.callbacks.ModelCheckpoint(output_model_file, save_best_only=True),\n",
    "    keras.callbacks.EarlyStopping(patience=5, min_delta=1e-3)\n",
    "]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/15\n",
      "1136/1136 [==============================] - 221s 195ms/step - loss: 1.4337 - accuracy: 0.6436 - val_loss: 0.0061 - val_accuracy: 0.9985\n",
      "Epoch 2/15\n",
      "1136/1136 [==============================] - 222s 195ms/step - loss: 0.2520 - accuracy: 0.9238 - val_loss: 0.0102 - val_accuracy: 0.9956\n",
      "Epoch 3/15\n",
      "1136/1136 [==============================] - 223s 196ms/step - loss: 0.1769 - accuracy: 0.9479 - val_loss: 0.0586 - val_accuracy: 0.9945\n",
      "Epoch 4/15\n",
      "1136/1136 [==============================] - 221s 195ms/step - loss: 0.1416 - accuracy: 0.9591 - val_loss: 1.4966e-07 - val_accuracy: 1.0000\n",
      "Epoch 5/15\n",
      "1136/1136 [==============================] - 220s 194ms/step - loss: 0.1353 - accuracy: 0.9630 - val_loss: 1.1921e-07 - val_accuracy: 1.0000\n",
      "Epoch 6/15\n",
      "1136/1136 [==============================] - 226s 199ms/step - loss: 0.1185 - accuracy: 0.9690 - val_loss: 1.1921e-07 - val_accuracy: 1.0000\n",
      "Epoch 7/15\n",
      "1136/1136 [==============================] - 224s 198ms/step - loss: 0.1202 - accuracy: 0.9706 - val_loss: 1.1921e-07 - val_accuracy: 1.0000\n",
      "Epoch 8/15\n",
      "1136/1136 [==============================] - 221s 195ms/step - loss: 0.1103 - accuracy: 0.9745 - val_loss: 1.1921e-07 - val_accuracy: 1.0000\n",
      "Epoch 9/15\n",
      "1136/1136 [==============================] - 222s 195ms/step - loss: 0.1145 - accuracy: 0.9751 - val_loss: 0.0012 - val_accuracy: 1.0000\n",
      "Epoch 10/15\n",
      "1136/1136 [==============================] - 229s 202ms/step - loss: 0.1131 - accuracy: 0.9761 - val_loss: 1.1921e-07 - val_accuracy: 1.0000\n",
      "Epoch 11/15\n",
      "1136/1136 [==============================] - 242s 213ms/step - loss: 0.1096 - accuracy: 0.9790 - val_loss: 1.1974e-07 - val_accuracy: 1.0000\n",
      "Epoch 12/15\n",
      "1136/1136 [==============================] - 239s 210ms/step - loss: 0.1181 - accuracy: 0.9783 - val_loss: 1.1921e-07 - val_accuracy: 1.0000\n",
      "Epoch 13/15\n",
      "1136/1136 [==============================] - 236s 208ms/step - loss: 0.1249 - accuracy: 0.9788 - val_loss: 1.1921e-07 - val_accuracy: 1.0000\n",
      "Epoch 14/15\n",
      "1136/1136 [==============================] - 241s 213ms/step - loss: 0.1162 - accuracy: 0.9813 - val_loss: 1.1921e-07 - val_accuracy: 1.0000\n",
      "Epoch 15/15\n",
      "1136/1136 [==============================] - 239s 211ms/step - loss: 0.1167 - accuracy: 0.9820 - val_loss: 1.1921e-07 - val_accuracy: 1.0000\n"
     ]
    }
   ],
   "source": [
    "epochs = 15\n",
    "#因为数据是generator 产生的 所以不能用fit函数\n",
    "history = model.fit_generator(train_generator, steps_per_epoch=train_num // batch_size,\n",
    "                             epochs=epochs, validation_data=valid_generator,\n",
    "                             validation_steps=valid_num//batch_size)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [],
   "source": [
    "def plot_learning_curves(history, label, epochs, min_value, max_value):\n",
    "    data = {}\n",
    "    data[label] = history.history[label]\n",
    "    data['val_'+label] = history.history['val_' + label]\n",
    "    \n",
    "    pd.DataFrame(data).plot(figsize = (8,5))\n",
    "    plt.grid(True)\n",
    "    plt.axis([0, epochs, min_value, max_value])\n",
    "    plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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KoxXrN/JpBGV1NUO8l2KiIhI1vSZMH5j1zFebTrKwrPHEDu3iIiISGHoM2G8ckMjpaEAX5022ncpIiIiWdUnwri1I8KjLzcx58wRVPXP6SmvRUREel2fCOOntuzhWGuYRboohIiIFKA+EcbLX2pk7JD+nPuJob5LERERybq8D+N3D7zPuh0HWXj2GAIBHbglIiKFJ+/DeMWGRoIBY/70Wt+liIiI5EReh3FHJMqqjU3MmjiM4QPLfZcjIiKSE3kdxs+9uY/9zW06cEtERApaXofxivWNDKsso35ije9SREREciZvw3jP0Vaee2sfC2bUEgrmbZkiIiIfW96m3KqNjUQdfG2GdlGLiEhhy8swjkYdKzY0ct4nh3La0AG+yxEREcmpvAzjdTsO0njoAxbqwC0RESkCeRnGy9c3MqhfCV88c4TvUkRERHIu78L48PvtPLV5D1+dNprykqDvckRERHIu78J49ab3aI9EtYtaRESKRl6FsXOOFesbqRtTxRkjB/ouR0REpFfkVRi/0niEt/Y264xbIiJSVPIqjFesb6R/aZAv143yXYqIiEivyZswbmkL89iru7hk6kgqykK+yxEREek1eRPG//HaLo63R1h49ljfpYiIiPSqvAnj5esbGT+sgrPGVvkuRUREpFflRRi/taeZTTuPsPDsMZiZ73JERER6VV6E8Yr1jZQEjUvPqvVdioiISK/zHsZt4QiPbmriojNHMGRAqe9yREREep33MP7PLXs5crxD3y0WEZGi5T2MV6xvZHRVP87/ZLXvUkRERLzwGsaNh47zh+0HWHj2GAIBHbglIiLFyWsYr1jfSMBg/nQduCUiIsXLaxj/dmMjF0yoYVRVP59liIiIeOUtjI+HHXuPtbFops64JSIixc1bGLe0Q3VFGRdOGuarBBERkbzgdct4/vRaSoLeD+gWERHxymsSLtR3i0VERPyFcWWpMa56gK+nFxERyRvewnhoub5XLCIiAnlwBi4REZFipzAWERHxTGEsIiLimcJYRETEM4WxiIiIZwpjERERzzIKYzObY2Zvmdl2M7ulmzH1ZvaKmW0xs+ezW6aIiEjhCvU0wMyCwM+BLwBNwHoze8w590bSmCrgn4E5zrmdZqYTTouIiGQoky3jmcB259wO51w7sByYlzLmL4FHnXM7AZxz+7JbpoiISOHKJIxHA41J003x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/v0tsOf17K5zxBS4+M5uF998882cdtppfOMb3wDgtttuw8xYu3Ythw8fpqOjgzvuuIN58+b1+FQtLS3Mmzcv8bhbb72VRYsWAfDQQw9x1113YWZMnTqVf/mXf2Hv3r1cc8017NixA4B7772XUaNGcckll7B582YA7rrrLlpaWrjtttuor6/nvPPO44UXXmDu3LlMmDCBO+64g/b2doYOHcrDDz/M8OHDaWlp4frrr2fDhg2YGT/4wQ84cuQImzdv5sc//jEAv/zlL9m6dWvaM36JiEju5W8Ye7Bo0SK++c1vJsJ45cqVPPnkk9x4440MHDiQAwcOcO655zJ37ty0V1VKVl5ezurVqxOPmzlzJgsXLuSNN97g7//+73nhhReorq5OXATihhtu4IILLmD16tVEIhFaWlp6vD7ykSNHeP7554HYRSpefPFFzIz77ruPH/3oR9x9991pr7lcWlrK1KlT+dGPfkRJSQkPPPAAv/jFLz7uyyciIh9R/obxKbZgc2XatGns27ePXbt2sX//fgYPHszIkSO58cYbWbt2LYFAgPfee4+9e/cyYsSIU67LOcd3v/vdxON2797N3r17efbZZ5k/fz7V1dXAiWsVP/vss4nrEweDQQYNGtRjGHdesAKgqamJhQsXsnv3btrb2xPXXu7umssXXnghjz/+OGeccQYdHR1MmTLlQ75aIiKSLfkbxp7Mnz+fVatWsWfPHhYtWsTDDz/M/v372bhxIyUlJZx++uknXaM4ndTHnXbaabS2tnZ7reJ0QqEQ0Wg0MX2qayNff/313HTTTcydO5eGhgZuu+02oPtrI1911VX88Ic/ZNKkSSxZsiSjekREJDd0AFeKRYsWsXz5clatWsX8+fM5evQow4YNo6SkhOeee44//elPGa0n9XE7d+4EYPbs2axcuZKDBw8CJ65VPHv2bO69914AIpEIx44dY/jw4ezbt4+DBw/S1tbG448/fsrn67w2cvKVpLq75vI555xDY2Mjv/nNb7jssssyfXlERCQHFMYpzjzzTJqbmxk9ejQjR47k8ssvZ8OGDcyYMYOHH36YSZMmZbSe1MdNmDAhsf5bb72VCy64gLq6Om666SYAfvKTn/Dcc88xZcoUpk+fzpYtWygpKeH73/8+55xzDpdccskpn/u2225jwYIFfO5zn0vsAofur7kM8LWvfY3zzz8/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\n",
      "text/plain": [
       "<Figure size 576x360 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plot_learning_curves(history, 'accuracy', epochs, 0, 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAeoAAAEzCAYAAAD+XEDdAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjIsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8li6FKAAAgAElEQVR4nO3de3Rc5Znn++9TpZJk3XwXlmxiG+zIFr4RwEDSbWSSgIEGkunMGhNCaLoTL04CnWSmcwKdGejOnO6Tbs70me4BQnsyDOGEQHwITCCYQLqDAnQgMaZtbGNsHIOxLBvfwJYs61JVz/yxS1JZlqySrVJd9u+zVq3a+93v3vU+vuinfam9zd0RERGR/BTJ9QBERERkaApqERGRPKagFhERyWMKahERkTymoBYREcljCmoREZE8NmxQm9nZZvaCmW01sy1m9rVB+piZ/YOZ7TCzN8zsY2nLVpjZttSyO0a7ABERkWKWyR51HPgP7j4fuAT4qpk1DuhzFTA39VoFfA/AzKLAfanljcANg6wrIiIiQxg2qN19r7u/nppuA7YC0wd0ux542AOvAhPMrA5YCuxw953u3g08luorIiIiGRjROWozmwWcD/xmwKLpwO60+ZZU21DtIiIikoGSTDuaWRXwE+Dr7n504OJBVvFTtA+2/VUEh80pLy+/4CMf+UimQytoyWSSSCQ81/SFqd4w1QrhqjdMtUK46s1Vrdu3bz/o7lMHW5ZRUJtZjCCkH3H3Jwbp0gKcnTY/A2gFSodoP4m7rwZWAzQ0NPi2bdsyGVrBa25upqmpKdfDGDNhqjdMtUK46g1TrRCuenNVq5ntGmpZJld9G/A/gK3u/ndDdHsK+GLq6u9LgCPuvhdYB8w1s9lmVgqsTPUVERGRDGSyR/0J4CZgk5ltSLX9OfARAHd/AFgLXA3sADqAW1LL4mZ2G/AcEAUedPcto1qBiIhIERs2qN39ZQY/15zex4GvDrFsLUGQi4iIyAhlfDGZiIjIUHp6emhpaaGzszPXQzkj48ePZ+vWrVnbfnl5OTNmzCAWi2W8joJaRETOWEtLC9XV1cyaNYvg0qbC1NbWRnV1dVa27e4cOnSIlpYWZs+enfF64bjeXkREsqqzs5PJkycXdEhnm5kxefLkER91UFCLiMioUEgP73T+jBTUIiJSFKqqqnI9hKxQUIuIiOQxBbWIiBQVd+eb3/wmCxYsYOHChfz4xz8GYO/evSxbtowlS5awYMECXnrpJRKJBH/0R3/U1/fee+/N8ehPpqu+RUSkqDzxxBNs2LCBjRs3cvDgQS666CKWLVvGj370I6688kq+/e1vk0gk6OjoYMOGDezZs4fNmzcDsHv37mG2PvYU1CIiMqr+8uktvNk68NlNZ6axvoa7rz0vo74vv/wyN9xwA9FolLPOOovLLruMdevWcdFFF/HHf/zH9PT08JnPfIYlS5ZwzjnnsHPnTm6//XauueYaLr300lEd92jQoW8RESkqwc0yT7Zs2TJefPFFpk+fzk033cTDDz/MxIkT2bhxI01NTdx3333cdtttYzza4WmPWkRERlWme77ZsmzZMv7xH/+Rm2++mcOHD/Piiy9yzz33sGvXLqZPn86Xv/xljh07xuuvv87VV19NaWkpf/iHf8i5557LF7/4xZyOfTAKahERKSqf/exneeWVV1i8eDFmxt/+7d8ybdo0fvCDH3DPPfcQi8Woqqri4YcfZs+ePdxyyy0kk0kA7r777hyP/mQKahERKQrt7e1AcFORe+65h3vuueeE5TfffDM333zzSeu9/vrrfdNtbW3ZHeRp0DlqERGRPKagFhERyWMKahERkTymoBYREcljCmoREZE8pqAWERHJYwpqERGRPKagFhGR0DnVs6vfffddFixYMIajOTUFtYiISB5TUIuISMH71re+xf333983/xd/8Rf85V/+JZ/85Cf52Mc+xsKFC/npT3864u12dnZyyy23sHDhQs4//3xeeOEFALZs2cLSpUtZsmQJixYt4u233+bYsWNcc801LF68mAULFvQ9B/tM6RaiIiIyup69A/ZtGt1tTlsIV313yMUrV67k61//Ol/5ylcAWLNmDT//+c/5xje+QU1NDQcPHuSSSy7huuuuw8wy/tj77rsPgE2bNvHWW29xxRVXsH37dh544AG+9rWvceONN9Ld3U0ikWDt2rXU19fzzDPPAHDkyJEzKLif9qhFRKTgnX/++ezfv5/W1lY2btzIxIkTqaur48///M9ZtGgRn/rUp9izZw/vv//+iLb78ssvc9NNNwEwb948Zs6cyfbt27n00kv567/+a/7mb/6GXbt2MW7cOBYuXMg//dM/8a1vfYuXXnqJ8ePHj0ptw+5Rm9mDwB8A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\n",
      "text/plain": [
       "<Figure size 576x360 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plot_learning_curves(history, 'loss', epochs, 0, 2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [],
   "source": [
    "def load_and_preprocess_single_img(path):\n",
    "    # read the img through file path\n",
    "    image = tf.io.read_file(path)  \n",
    "    image = tf.image.decode_jpeg(image, channels=3)\n",
    "    # 原始图片大小为(128, 128, 3)，重设为(32, 32)\n",
    "    image = tf.image.resize(image, [32, 32])  \n",
    "    image = tf.cast(image, tf.float32) / 255.0  # 归一化到[0,1]范围\n",
    "    image = np.expand_dims(image, axis = 0) # since you have batch_size, so you need to expand your image\n",
    "    return image"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [],
   "source": [
    "def evaluate_single_pic(path, show=False):\n",
    "    \n",
    "    if show:\n",
    "        import matplotlib.image as mpimg\n",
    "        plt.imshow(mpimg.imread(path))\n",
    "    image = load_and_preprocess_single_img(path)\n",
    "    predict_result = model.predict(image)\n",
    "    print(\"This is\", label_names[np.argmax(predict_result, axis=1)[0]])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [],
   "source": [
    "model.save_weights('./checkpoints/my_checkpoint2')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [],
   "source": [
    "model.save('./in_game_profile_model.h5')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [],
   "source": [
    "# test_pic_path2 = \"./lol_data_1/test_2/18.png\"\n",
    "# evaluate_single_pic(test_pic_path2, True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "TensorFlow-GPU",
   "language": "python",
   "name": "tf2_gpu"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
